home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland Pascal with Objects 7.0 / DDEML.ZIP / DDEMLCLI.PAS < prev    next >
Pascal/Delphi Source File  |  1992-10-27  |  13KB  |  449 lines

  1. {***************************************************}
  2. {                                                   }
  3. {   Windows 3.1 DDEML Demonstration Program         }
  4. {   Copyright (c) 1992 by Borland International     }
  5. {                                                   }
  6. {***************************************************}
  7.  
  8. program DDEMLClient;
  9.  
  10. { This is a sample application demonstrating the use of the DDEML APIs in
  11.   a client application.  It uses the DataEntry server application that
  12.   is part of this demo in order to maintain a display of the entered data
  13.   as a bar graph.
  14.  
  15.   You must run the server application first (in DDEMLSRV.PAS), and then
  16.   run this client.  If the server is not running, this application will
  17.   fail trying to connect.
  18.  
  19.   The interface to the server is defined by the list of names (Service,
  20.   Topic, and Items) in the separate unit called DataEntry (DATAENTR.TPU).
  21.   The server makes the Items available in cf_Text format; they are con-
  22.   verted and stored locally as integers.
  23. }
  24.  
  25. uses Strings, WinTypes, WinProcs, OWindows, ODialogs, Win31, DDEML,
  26.   ShellAPI, BWCC, DataEntry;
  27.  
  28. {$R DDEMLCLI}
  29.  
  30. const
  31.  
  32. { Resource IDs }
  33.  
  34.   id_Menu  = 100;
  35.   id_About = 100;
  36.   id_Icon  = 100;
  37.  
  38.   id_PokeEdit = 201;    { Edit Control in Poke Data dialog }
  39.  
  40. { Menu command IDs }
  41.  
  42.   cm_Request   = 200;
  43.   cm_Poke      = 201;
  44.   cm_Advise    = 202;
  45.   cm_HelpAbout = 300;
  46.  
  47. type
  48.  
  49. { Application main window }
  50.  
  51.   PDDEClientWindow = ^TDDEClientWindow;
  52.   TDDEClientWindow = object(TWindow)
  53.     Inst: Longint;
  54.     CallBackPtr: ^TCallback;
  55.     ServiceHSz : HSz;
  56.     TopicHSz   : HSz;
  57.     ItemHSz    : array [1..NumValues] of HSz;
  58.     ConvHdl    : HConv;
  59.  
  60.     DataSample : TDataSample;
  61.  
  62.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  63.     destructor  Done; virtual;
  64.  
  65.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  66.     function  GetClassName: PChar; virtual;
  67.     procedure SetupWindow; virtual;
  68.  
  69.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  70.  
  71.     procedure CMRequest(var Msg: TMessage);
  72.       virtual cm_First + cm_Request;
  73.     procedure CMPoke(var Msg: TMessage);
  74.       virtual cm_First + cm_Poke;
  75.     procedure CMAdvise(var Msg: TMessage);
  76.       virtual cm_First + cm_Advise;
  77.     procedure CMHelpAbout(var Msg: TMessage);
  78.       virtual cm_First + cm_HelpAbout;
  79.  
  80.     procedure Request(HConversation: HConv); virtual;
  81.   end;
  82.  
  83. { Application object }
  84.  
  85.   TDDEClientApp = object(TApplication)
  86.     procedure InitMainWindow; virtual;
  87.   end;
  88.  
  89. { Initialized globals }
  90.  
  91. const
  92.   DemoTitle : PChar = 'DDEML Demo, Client Application';
  93.  
  94. { Global variables }
  95.  
  96. var
  97.   App: TDDEClientApp;
  98.  
  99.  
  100. { Local Function: CallBack Procedure for DDEML }
  101.  
  102. function CallbackProc(CallType, Fmt: Word; Conv: HConv; hsz1, hsz2: HSZ;
  103.   Data: HDDEData; Data1, Data2: Longint): HDDEData; export;
  104. var
  105.   ThisWindow: PDDEClientWindow;
  106. begin
  107.   CallbackProc := 0;    { See if proved otherwise }
  108.  
  109.   ThisWindow := PDDEClientWindow(App.MainWindow);
  110.  
  111.   case CallType of
  112.     xtyp_Register:
  113.       begin
  114.         { Nothing ... Just return 0 }
  115.       end;
  116.     xtyp_Unregister:
  117.       begin
  118.         { Nothing ... Just return 0 }
  119.       end;
  120.     xtyp_xAct_Complete:
  121.       begin
  122.         { Nothing ... Just return 0 }
  123.       end;
  124.     xtyp_Request, Xtyp_AdvData:
  125.       begin
  126.         ThisWindow^.Request(Conv);
  127.         CallbackProc := dde_FAck;
  128.       end;
  129.     xtyp_Disconnect:
  130.       begin
  131.     MessageBox(ThisWindow^.HWindow, 'Disconnected!',
  132.       Application^.Name, mb_IconStop);
  133.         PostQuitMessage(0);
  134.       end;
  135.   end;
  136. end;
  137.  
  138.  
  139. { TDDEClientWindow Methods }
  140.  
  141. { Constructs an instance of the DDE Client Window.  Constructs the 
  142.   window using the inherited constructor, then initializes the instance
  143.   data.
  144. }
  145. constructor TDDEClientWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  146. var
  147.   I : Integer;
  148. begin
  149.   TWindow.Init(AParent, ATitle);
  150.  
  151.   Inst       := 0;      { Must be zero for first call to DdeInitialize } 
  152.   CallBackPtr:= nil;    { MakeProcInstance is called in SetupWindow    }
  153.   ConvHdl    := 0;
  154.   ServiceHSz := 0;
  155.   TopicHSz   := 0;
  156.   for I := 1 to NumValues do
  157.   begin
  158.     ItemHSz[I]    := 0;
  159.     DataSample[I] := 0;
  160.   end;
  161. end;
  162.  
  163. { Destroys an instance of the Client window.  Frees the DDE string
  164.   handles, and frees the callback proc instance if they exist.  Also 
  165.   calls DdeUninitialize to terminate the conversation.  Then calls on
  166.   the ancestral destructor to finish the job.
  167. }
  168. destructor TDDEClientWindow.Done;
  169. var
  170.   I : Integer;
  171. begin
  172.   if ServiceHSz <> 0 then
  173.     DdeFreeStringHandle(Inst, ServiceHSz);
  174.   if TopicHSz <> 0 then
  175.     DdeFreeStringHandle(Inst, TopicHSz);
  176.   for I := 1 to NumValues do
  177.     if ItemHSz[I] <> 0 then
  178.       DdeFreeStringHandle(Inst, ItemHSz[I]);
  179.  
  180.   if Inst <> 0 then
  181.     DdeUninitialize(Inst);   { Ignore the return value }
  182.  
  183.   if CallBackPtr <> nil then
  184.     FreeProcInstance(CallBackPtr);
  185.  
  186.   TWindow.Done;
  187. end;
  188.  
  189. { Redefines GetWindowClass to give this application its own Icon, and 
  190.   its own menu.
  191. }
  192. procedure TDDEClientWindow.GetWindowClass(var AWndClass: TWndClass);
  193. begin
  194.   TWindow.GetWindowClass(AWndClass);
  195.   AWndClass.hIcon := LoadIcon(AWndClass.hInstance, PChar(id_Icon));
  196.   AWndClass.lpszMenuName := PChar(id_Menu);
  197. end;
  198.  
  199. { Returns the class name of this window.  This is necessary since we
  200.   redefine the inherited GetWindowClass method, above.
  201. }
  202. function TDDEClientWindow.GetClassName: PChar;
  203. begin
  204.   GetClassName := 'TDDEClientWindow';
  205. end;
  206.  
  207. { Completes the initialization of the DDE Server Window.  Performs those 
  208.   actions which require a valid window.  Initializes the use of the DDEML.
  209. }
  210. procedure TDDEClientWindow.SetupWindow;
  211. var
  212.   I     : Integer;
  213.   InitOK: Boolean;
  214. begin
  215.   CallBackPtr := MakeProcInstance(@CallBackProc, HInstance);
  216.  
  217. { Initialize the DDE and setup the callback function. If server is not
  218.   present, call will fail.
  219. }
  220.   if CallBackPtr <> nil then
  221.   begin
  222.     if DdeInitialize(Inst, TCallback(CallBackPtr), AppCmd_ClientOnly,
  223.       0) = dmlErr_No_Error then
  224.     begin
  225.       ServiceHSz:= DdeCreateStringHandle(Inst, DataEntryName, cp_WinAnsi);
  226.       TopicHSz  := DdeCreateStringHandle(Inst, DataTopicName, cp_WinAnsi);
  227.       InitOK := True;
  228.       for I := 1 to NumValues do
  229.       begin
  230.     ItemHSz[I]:= DdeCreateStringHandle(Inst, DataItemNames[I],
  231.       cp_WinAnsi);
  232.         InitOK := InitOK and (ItemHSz[I] <> 0); 
  233.       end;
  234.  
  235.       if (ServiceHSz <> 0) and (TopicHSz <> 0) and InitOK then
  236.       begin
  237.         ConvHdl := DdeConnect(Inst, ServiceHSz, TopicHSz, nil);
  238.         if ConvHdl = 0 then
  239.         begin
  240.       MessageBox(HWindow, 'Can''t start conversation!',
  241.         Application^.Name, mb_IconStop);
  242.           PostQuitMessage(0);
  243.         end
  244.       end
  245.       else
  246.       begin  
  247.     MessageBox(HWindow, 'Can''t create strings!', Application^.Name,
  248.       mb_IconStop);
  249.         PostQuitMessage(0);
  250.       end
  251.     end
  252.     else
  253.     begin
  254.       MessageBox(HWindow, 'Can''t initialize!', Application^.Name,
  255.         mb_IconStop);
  256.       PostQuitMessage(0);
  257.     end;
  258.   end;
  259. end;
  260.  
  261. { Repaints the window on request.  Plots a graph of the current sales
  262.   volume.
  263. }
  264. procedure TDDEClientWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  265. const
  266.   LMarg = 30;    { Left Margin of graph }
  267. var
  268.   Wd, Mid: Integer;
  269.   Step   : Integer;
  270.   I      : Integer;
  271.   Norm   : Integer;
  272.   CRect  : TRect;
  273.   ARect  : TRect;
  274.   ALabel : array [0..10] of Char;
  275.   TextMet: TTextMetric;
  276. begin
  277. { First, find the maximum value, and compute a normalization
  278.   factor based on it.
  279. }
  280.   Norm := 0;
  281.   for I := 1 to NumValues do
  282.   begin
  283.     if abs(DataSample[I]) > Norm then
  284.       Norm := abs(DataSample[I]);
  285.   end;
  286.   if Norm = 0 then Norm := 1;   { Just in case we have all zeros }
  287.  
  288. { Next, paint and label the axes.
  289. }
  290.   GetTextMetrics(PaintDC, TextMet);
  291.   GetClientRect(HWindow, CRect);
  292.   Mid := CRect.Bottom div 2;
  293.   MoveTo(PaintDC, 0, Mid);
  294.   LineTo(PaintDC, CRect.Right, Mid);
  295.   MoveTo(PaintDC, LMarg,      0);
  296.   LineTo(PaintDC, LMarg, CRect.Bottom);
  297.   Str(Norm, ALabel);
  298.   TextOut(PaintDC, 0,0, ALabel, StrLen(ALabel));
  299.   TextOut(PaintDC, 0, Mid-(TextMet.tmHeight div 2), '0', 1);
  300.   Str(-Norm, ALabel);
  301.   TextOut(PaintDC, 0,CRect.Bottom-TextMet.tmHeight, ALabel, StrLen(ALabel));
  302.  
  303. { Now draw the bars based on that Normalized value.  Compute the width
  304.   of the bars so that all will fit in the window, and compute an inter-
  305.   bar space that is approximately 20% of the width of a bar.
  306. }
  307.   SelectObject(PaintDC, CreateSolidBrush(RGB(255, 0, 0)));
  308.   SetBkMode(PaintDC, Transparent);
  309.  
  310.   Wd  := (CRect.Right - LMarg) div NumValues;
  311.   Step:= Wd div 5;
  312.   Wd  := Wd - Step;
  313.   ARect.Left := LMarg + (Step div 2);
  314.   for I := 1 to NumValues do
  315.   begin
  316.     with ARect do
  317.     begin
  318.       Right := Left + Wd;
  319.       Top   := Mid;
  320.       Bottom:= Top - Round((Top-5) * (DataSample[I] / Norm));
  321.       Rectangle(PaintDC, Left, Top, Right, Bottom);
  322.       Bottom:= Top + 20;
  323.       DrawText(PaintDC, DataItemNames[I], -1, ARect, dt_Center);
  324.       Left := Left + Wd + Step;
  325.     end;
  326.   end;
  327.   DeleteObject(SelectObject(PaintDC, GetStockObject(White_Brush)));
  328. end;
  329.  
  330. { Generate a DDE Request in response to the DDE | Request menu selection.
  331. }
  332. procedure TDDEClientWindow.CMRequest(var Msg: TMessage);
  333. begin
  334.   Request(ConvHdl);
  335. end;
  336.  
  337. { Generates a DDE Poke transaction in response to the DDE | Poke
  338.   menu selection.  Requests a value from the user that will be
  339.   poked into DataItem1 as an illustration of the Poke function.
  340. }
  341. procedure TDDEClientWindow.CMPoke(var Msg: TMessage);
  342. var
  343.   DataStr: TDataString;
  344.   PokeDlg: PDialog;
  345.   Ed     : PEdit;
  346. begin
  347.   PokeDlg := New(PDialog, Init(@Self, 'POKEDATA'));
  348.   New(Ed, InitResource(PokeDlg, id_PokeEdit, SizeOf(DataStr)));
  349.   StrCopy(DataStr, '0');
  350.   PokeDlg^.TransferBuffer := @DataStr;
  351.  
  352.   if Application^.ExecDialog(PokeDlg) = IdOK then
  353.   begin
  354.     DdeClientTransaction(@DataStr, StrLen(DataStr) + 1, ConvHdl,
  355.       ItemHSz[1], cf_Text, xtyp_Poke, 1000, nil);
  356.     Request(ConvHdl);
  357.   end;
  358. end;
  359.  
  360. { Toggles the state of the DDE Advise setting in response to the
  361.   DDE | Advise menu selection.  When this is selected, all three
  362.   Items are set for Advising.
  363. }
  364. procedure TDDEClientWindow.CMAdvise(var Msg: TMessage);
  365. var
  366.   TempMenu  : HMenu;
  367.   TempResult: Longint;
  368.   I         : Integer;
  369.   NewState  : Word;
  370.   TransType : Word;
  371. begin
  372.   TempMenu := GetMenu(HWindow);
  373.   if GetMenuState(TempMenu, Msg.WParam, mf_ByCommand) = mf_Unchecked then
  374.   begin
  375.     NewState := mf_Checked;
  376.     TransType:= (xtyp_AdvStart or xtypf_AckReq);
  377.   end
  378.   else
  379.   begin
  380.     NewState := mf_Unchecked;
  381.     TransType:= xtyp_AdvStop;
  382.   end;
  383.  
  384.   for I := 1 to NumValues do
  385.     if DdeClientTransaction(nil, 0, ConvHdl, ItemHSz[I], cf_Text, TransType,
  386.         1000, @TempResult) = 0 then
  387.       MessageBox(HWindow, 'Cannot perform Advise Transaction',
  388.           Application^.Name, mb_IconStop);
  389.  
  390.   CheckMenuItem(TempMenu, Msg.WParam, (mf_ByCommand or NewState));
  391.   DrawMenuBar(HWindow);
  392.  
  393.   if TransType and xtyp_AdvStart <> 0 then Request(ConvHdl);
  394. end;
  395.  
  396. { Posts the about box dialog for the DDE Client.
  397. }
  398. procedure TDDEClientWindow.CMHelpAbout(var Msg: TMessage);
  399. begin
  400.   Application^.ExecDialog(New(PDialog, Init(@Self, PChar(id_About))));
  401. end;
  402.  
  403. { Posts a DDE request to obtain cf_Text data from the server.  Requests
  404.   the data for all fields of the DataSample, and invalidates the window to
  405.   cause the new data to be displayed.  Obtains the data from the Server
  406.   synchronously, using DdeClientTransaction.
  407. }
  408. procedure TDDEClientWindow.Request(HConversation: HConv);
  409. var
  410.   hDdeTemp : HDDEData;
  411.   DataStr  : TDataString;
  412.   Err, I   : Integer;
  413. begin
  414.   if HConversation <> 0 then
  415.   begin
  416.     for I := 1 to NumValues do
  417.     begin
  418.       hDdeTemp := DdeClientTransaction(nil, 0, HConversation, ItemHSz[I],
  419.         cf_Text, xtyp_Request, 0, nil);
  420.       if hDdeTemp <> 0 then
  421.       begin
  422.         DdeGetData(hDdeTemp, @DataStr, SizeOf(DataStr), 0);
  423.         Val(DataStr, DataSample[I], Err);
  424.       end;
  425.     end;
  426.     InvalidateRect(HWindow, nil, True);
  427.   end;
  428. end;
  429.  
  430.  
  431. { TDDEClientApp Methods }
  432.  
  433. { Constructs an instance of the DDE Client Window and installs it as the
  434.   MainWindow of this application.
  435. }
  436. procedure TDDEClientApp.InitMainWindow;
  437. begin
  438.   MainWindow := New(PDDEClientWindow, Init(nil, Application^.Name));
  439. end;
  440.  
  441.  
  442. { Main program }
  443.  
  444. begin
  445.   App.Init(DemoTitle);
  446.   App.Run;
  447.   App.Done;
  448. end.
  449.